; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s

; TEST 1 - negative.

; void *G;
; void *foo(){
;   void *V = malloc(4);
;   G = V;
;   return V;
; }

@G = external global i8*

; CHECK: define i8* @foo()
define i8* @foo() {
  %1 = tail call noalias i8* @malloc(i64 4)
  store i8* %1, i8** @G, align 8
  ret i8* %1
}

declare noalias i8* @malloc(i64)

; TEST 2
; call noalias function in return instruction.

; CHECK: define noalias i8* @return_noalias()
define i8* @return_noalias(){
  %1 = tail call noalias i8* @malloc(i64 4)
  ret i8* %1
}

define void @nocapture(i8* %a){
  ret void
}

; CHECK: define noalias i8* @return_noalias_looks_like_capture()
define i8* @return_noalias_looks_like_capture(){
  %1 = tail call noalias i8* @malloc(i64 4)
  call void @nocapture(i8* %1)
  ret i8* %1
}

declare i8* @alias()

; TEST 3
; CHECK: define i8* @call_alias()
; CHECK-NOT: noalias
define i8* @call_alias(){
  %1 = tail call i8* @alias()
  ret i8* %1
}

; TEST 4
; void *baz();
; void *foo(int a);
;
; void *bar()  {
;   foo(0);
;    return baz();
; }
;
; void *foo(int a)  {
;   if (a)
;   bar();
;   return malloc(4);
; }

; CHECK: define i8* @bar()
define i8* @bar() nounwind uwtable {
  %1 = tail call i8* (...) @baz()
  ret i8* %1
}

; CHECK: define noalias i8* @foo1(i32 %0)
define i8* @foo1(i32 %0) nounwind uwtable {
  %2 = icmp eq i32 %0, 0
  br i1 %2, label %5, label %3

3:                                                ; preds = %1
  %4 = tail call i8* (...) @baz()
  br label %5

5:                                                ; preds = %1, %3
  %6 = tail call noalias i8* @malloc(i64 4)
  ret i8* %6
}

declare i8* @baz(...) nounwind uwtable

; TEST 5

; Returning global pointer. Should not be noalias.
; CHECK: define nonnull align 8 dereferenceable(8) i8** @getter()
define i8** @getter() {
  ret i8** @G
}

; Returning global pointer. Should not be noalias.
; CHECK: define nonnull align 8 dereferenceable(8) i8** @calle1()
define i8** @calle1(){
  %1 = call i8** @getter()
  ret i8** %1
}

; TEST 6
declare noalias i8* @strdup(i8* nocapture) nounwind

; CHECK: define noalias i8* @test6()
define i8* @test6() nounwind uwtable ssp {
  %x = alloca [2 x i8], align 1
  %arrayidx = getelementptr inbounds [2 x i8], [2 x i8]* %x, i64 0, i64 0
  store i8 97, i8* %arrayidx, align 1
  %arrayidx1 = getelementptr inbounds [2 x i8], [2 x i8]* %x, i64 0, i64 1
  store i8 0, i8* %arrayidx1, align 1
  %call = call noalias i8* @strdup(i8* %arrayidx) nounwind
  ret i8* %call
}

; TEST 7

; CHECK: define noalias i8* @test7()
define i8* @test7() nounwind {
entry:
  %A = call noalias i8* @malloc(i64 4) nounwind
  %tobool = icmp eq i8* %A, null
  br i1 %tobool, label %return, label %if.end

if.end:
  store i8 7, i8* %A
  br label %return

return:
  %retval.0 = phi i8* [ %A, %if.end ], [ null, %entry ]
  ret i8* %retval.0
}

; TEST 8

; CHECK: define noalias i8* @test8(i32* %0)
define i8* @test8(i32* %0) nounwind uwtable {
  %2 = tail call noalias i8* @malloc(i64 4)
  %3 = icmp ne i32* %0, null
  br i1 %3, label %4, label %5

4:                                                ; preds = %1
  store i8 10, i8* %2
  br label %5

5:                                                ; preds = %1, %4
  ret i8* %2
}

; TEST 9
; Simple Argument Test
define internal void @test9(i8* %a, i8* %b) {
; CHECK: define internal void @test9(i8* noalias nocapture readnone %a, i8* nocapture readnone %b)
  ret void
}
define void @test9_helper(i8* %a, i8* %b) {
  tail call void @test9(i8* noalias %a, i8* %b)
  tail call void @test9(i8* noalias %b, i8* noalias %a)
  ret void
}


; TEST 10
; Simple CallSite Test

declare void @test10_helper_1(i8* %a)
define void @test10_helper_2(i8* noalias %a) {
  ret void
}
define void @test10(i8* noalias %a) {
; CHECK: define void @test10(i8* noalias %a)
; FIXME: missing noalias
; CHECK-NEXT:   tail call void @test10_helper_1(i8* %a)
  tail call void @test10_helper_1(i8* %a)

; CHECK-NEXT:   tail call void @test10_helper_2(i8* noalias %a)
  tail call void @test10_helper_2(i8* %a)
  ret void
}

; TEST 11
; CallSite Test

declare void @test11_helper(i8* %a, i8 *%b)
define void @test11(i8* noalias %a) {
; CHECK: define void @test11(i8* noalias %a)
; CHECK-NEXT:   tail call void @test11_helper(i8* %a, i8* %a)
  tail call void @test11_helper(i8* %a, i8* %a)
  ret void
}


; TEST 12
; CallSite Argument
declare void @use_nocapture(i8* nocapture)
declare void @use(i8*)
define void @test12_1() {
; CHECK-LABEL: @test12_1(
; CHECK-NEXT:    [[A:%.*]] = alloca i8, align 4
; CHECK-NEXT:    [[B:%.*]] = tail call noalias i8* @malloc(i64 4)
; CHECK-NEXT:    tail call void @use_nocapture(i8* noalias nonnull align 4 dereferenceable(1) [[A]])
; CHECK-NEXT:    tail call void @use_nocapture(i8* noalias nonnull align 4 dereferenceable(1) [[A]])
; CHECK-NEXT:    tail call void @use_nocapture(i8* noalias nocapture [[B]])
; CHECK-NEXT:    tail call void @use_nocapture(i8* noalias [[B]])
; CHECK-NEXT:    ret void
;
  %A = alloca i8, align 4
  %B = tail call noalias i8* @malloc(i64 4)
  tail call void @use_nocapture(i8* %A)
  tail call void @use_nocapture(i8* %A)
  tail call void @use_nocapture(i8* %B)
  tail call void @use_nocapture(i8* %B)
  ret void
}

define void @test12_2(){
; CHECK-LABEL: @test12_2(
; CHECK-NEXT:    [[A:%.*]] = tail call noalias i8* @malloc(i64 4)
; FIXME: This should be @use_nocapture(i8* noalias [[A]])
; CHECK-NEXT:    tail call void @use_nocapture(i8* nocapture [[A]])
; FIXME: This should be @use_nocapture(i8* noalias [[A]])
; CHECK-NEXT:    tail call void @use_nocapture(i8* [[A]])
; CHECK-NEXT:    tail call void @use(i8* [[A]])
; CHECK-NEXT:    tail call void @use_nocapture(i8* [[A]])
; CHECK-NEXT:    ret void
;
  %A = tail call noalias i8* @malloc(i64 4)
  tail call void @use_nocapture(i8* %A)
  tail call void @use_nocapture(i8* %A)
  tail call void @use(i8* %A)
  tail call void @use_nocapture(i8* %A)
  ret void
}

declare void @two_args(i8* nocapture , i8* nocapture)
define void @test12_3(){
; CHECK-LABEL: @test12_3(
  %A = tail call noalias i8* @malloc(i64 4)
; CHECK: tail call void @two_args(i8* nocapture %A, i8* %A)
  tail call void @two_args(i8* %A, i8* %A)
  ret void
}

define void @test12_4(){
; CHECK-LABEL: @test12_4(
  %A = tail call noalias i8* @malloc(i64 4)
  %B = tail call noalias i8* @malloc(i64 4)
  %A_0 = getelementptr i8, i8* %A, i64 0
  %A_1 = getelementptr i8, i8* %A, i64 1
  %B_0 = getelementptr i8, i8* %B, i64 0

; CHECK: tail call void @two_args(i8* noalias %A, i8* noalias %B)
  tail call void @two_args(i8* %A, i8* %B)

; CHECK: tail call void @two_args(i8* %A, i8* nocapture %A_0)
  tail call void @two_args(i8* %A, i8* %A_0)

; CHECK: tail call void @two_args(i8* %A, i8* %A_1)
  tail call void @two_args(i8* %A, i8* %A_1)

; FIXME: This should be @two_args(i8* noalias %A_0, i8* noalias %B_0)
; CHECK: tail call void @two_args(i8* %A_0, i8* nocapture %B_0)
  tail call void @two_args(i8* %A_0, i8* %B_0)
  ret void
}
